#!/usr/bin/env python3
# vim: tabstop=4 expandtab

import random
import string
import time
from datetime import datetime
from os import getenv
from pathlib import Path
from urllib.parse import unquote

from gemini_antenna.db import AntennaDB
from gemini_antenna.signoffs import getsig

def randomFileName() -> str:
    return ''.join(random.choice(string.ascii_letters) for x in range(32))

def createFilterFile(dataroot: Path, timestamp: int) -> None:
    """
    :param dataroot: Antenna data directory.
    :param timestamp: Seconds since epoch.
    """
    if getenv('QUERY_STRING', default="n").lower() not in ("y", "ye", "yes"):
        print("10 Type 'y' if you want to create a filter, otherwise go back.",
              end="\r\n")
        return

    filterFilePath = Path()
    while filterFilePath.exists():
        filterName = randomFileName()
        filterFilePath = Path(dataroot / "customfilters" / filterName)

    filterFilePath.parent.mkdir(parents=True, exist_ok=True)
    with open(filterFilePath, "w") as file:
        print("Last Read:", timestamp, end="\n\n", file=file)

    # relative redirect
    print(f"30 {getenv('SCRIPT_NAME', '')}/{filterName}", end="\r\n")

def addRule(filterName: str, rules: list[str], **kwargs) -> None:
    affectedRule = unquote(getenv('QUERY_STRING', default=""))
    if not affectedRule:
        print("10 Rule to add:", end="\r\n")
        return

    if affectedRule not in rules:
        rules.insert(0, affectedRule)
    # relative redirect
    print(f"30 {getenv('SCRIPT_NAME', '')}/{filterName}", end="\r\n")

def removeRule(filterName: str, rules: list[str], **kwargs) -> None:
    affectedRule = unquote(getenv('QUERY_STRING', default=""))
    if not affectedRule:
        print("10 Rule to remove:", end="\r\n")
        return

    if affectedRule in rules:
        rules.remove(affectedRule)
    # relative redirect
    print(f"30 {getenv('SCRIPT_NAME', '')}/{filterName}", end="\r\n")

def readRules(filterName: str, rules: list[str], *, db: AntennaDB) -> None:
    print("20 text/gemini", end="\r\n")
    print("# Your Filter Rules", end="\n\n")
    if not rules:
        print(
            "Bookmark this URL. It's your personal filter. It'll be here "
            "forever if you check it often, but if you don't check it in 90 "
            "days it'll be removed.", end="\n\n"
        )
        print(
            "You should add some rules here! The way it works is that any link "
            "on Antenna that starts with a matching rule is removed from this "
            "view.", end="\n\n")
        print(
            'For example: the rule "gemini://rockstar" will remove every link '
            'starting with that, including "gemini://rockstar.com/posts/1" or '
            '"gemini://rockstarfamily.org"', end="\n\n"
        )

    for rule in rules:
        print(f"=> remove?{rule} {rule} (Click to remove)")
    print()

    feedURLSet = set()
    for entry in db.getEntries():
        if entry.feedurl not in rules:
            feedURLSet.add(entry.feedurl)

    for feedURL in feedURLSet:
        print("=>", f"add?{feedURL} Click to block '{feedURL}'")
    print("\n=> add Click to add custom rule")

def filteredFeed(filterName: str, rules: list[str], *, db: AntennaDB) -> None:
    """ This is where we end up when we just want to read the feed. """
    print("20 text/gemini", end="\r\n")
    print("=>", f"{getenv('SCRIPT_NAME', '')}/{filterName}/read Configure your filter.",
          end="\n\n")

    print("# Your Filtered Feed")
    datestamp = "0000-00-00"
    for entry in db.getEntries():
        blocked = False
        for rule in rules:
            if entry.link.startswith(rule) or entry.feedurl.startswith(rule):
                blocked = True
                break
        if blocked:
            continue
        timestamp = datetime.utcfromtimestamp(entry.updated).strftime('%Y-%m-%d')
        if not datestamp == timestamp:
            datestamp = timestamp
            print()
        print("=>", f"{entry.link} {timestamp} {entry.author}: {entry.title}",
              end="\n\n")

    print(">", getsig())

def app() -> None:
    ACTIONS={
        "add": addRule,
        "remove": removeRule,
        "read": readRules
    }

    pathInfo = getenv('PATH_INFO', default="")
    filterParts = pathInfo.split("/")
    if "" in filterParts:
        filterParts.remove("")

    dataroot = Path(getenv('ANTENNA_DATAROOT', default=str(Path.cwd())))
    db = AntennaDB(dataroot / "antenna.sqlite")
    timestamp = int(time.mktime(datetime.utcnow().utctimetuple()))

    if (not pathInfo
        or not Path(dataroot / "customfilters" / filterParts[0]).exists()):
        createFilterFile(dataroot, timestamp)
        return

    # If we reached this, that means filter exists
    filterName = filterParts[0]
    action = filterParts[-1]

    filterFilePath = Path(dataroot / "customfilters" / filterName)
    with open(filterFilePath) as f:
        rules = f.read().split("\n")

    rules = list(filter(None, rules))
    rules.pop(0)

    ACTIONS.get(action, filteredFeed)(filterName, rules, db=db)

    filterFilePath.unlink()
    with open(filterFilePath, "a") as file:
        print("Last Read:", timestamp, end="\n\n", file=file)
        print(*rules, sep="\n", file=file)

def main() -> None:
    # TODO: handle exceptions
    app()

if __name__ == "__main__":
    main()
